/**************************************************************************************************
 * 表单验证工具JS，目前支持必填验证，正则表达式验证，最大值验证，最小值验证，最大长度验证，最小长度验证，常用数据类型验证
 * 注意：如果字段不是必须填写项，且没有输入值的话将不进行其他格式的验证。
 * 使用方法：
 * 1.页面引入本js文件
 * 2.html字段加上必须属性
 * 如：<input required="true" requiredMsg="必填项" regex="^0?(86)?1[3,5]\d{9}$" regexMsg="请输入正确的手机号码" />
 * 3.在body onload时加上函数initValidateForm(form)
 *
 * 各种验证对应的属性如下：
 * 必填验证:required="true" 正则表达式验证:regex 最大值:maxValue 最小值:minValue
 * 最大长度:maxLen 最小长度:minLen
 *
 * 支持常用数据类型验证
 * 如：<input dataType="mobilePhone" dataTypeMsg="请输入正确的手机号码" />
 * 各种数据类型对应如下：
 * 手机号码:mobilePhone 座机号码:telephone 电话号码:phone email:email 邮编:zipCode 日期:date 
 * 整数:integer 小数:float 身份证:identity
 *
 * @author 潘海春
 * @date 2008-10-22
 **************************************************************************************************/


//---一组常用的正则表达式-----------------------------------------------

var favoriteRegExp = new Array();

//手机
favoriteRegExp["mobilePhone"] = /^0?(86-?)?1[3,5,8]\d{9}$/;
//座机
favoriteRegExp["telphone"] = /^((0?86-\d{2,3}-)|(0\d{2,3}-))?\d{7,8}(-\d{3,})?$/;
//手机或者座机
favoriteRegExp["phone"] = /(^0?(86-?)?1[3,5,8]\d{9}$)|(^((0?86-\d{2,3}-)|(0\d{2,3}-))?\d{7,8}(-\d{3,})?$)/;
//email
favoriteRegExp["email"] = /^\w+((-\w+)|(\.\w+))*@[A-Za-z0-9]+((\.|-)[A-Za-z0-9]+)*\.[A-Za-z0-9]+$/;
//邮编
favoriteRegExp["zipCode"] = /^\d{6}$/;
//日期
favoriteRegExp["date"] = /^([1-9]\d{3}-(((0[13578]|1[02])-(0[1-9]|[12]\d|3[01]))|((0[469]|11)-(0[1-9]|[12]\d|30))|(02\-(0[1-9]|[1]\d|2[0-8]))))|(((\d{2})(0[48]|[2468][048]|[13579][26])|((0[48]|[2468][048]|[3579][26])00))-02-29)$/;
//整数
favoriteRegExp["integer"] = /^(0|([+,-]?[1-9]\d*))$/;
//小数
favoriteRegExp["float"] = /^(0|([+,-]?[1-9]\d*))(\.\d*)?$/;
//身份证
favoriteRegExp["identity"] = /^\d{17}[X,x,Y,y,\d]$/;

/**
 * Function:验证器接口
 * PublicMethod validate 验证方法
 */
function Validator() {
}
Validator.prototype.validate = function(value) {
}

/**
 * Function:验证器抽象基类
 * @Extend Validator
 * @PrivateProperty errorMsg 出错显示的错误信息文本
 * @PublicMethod getErrorMsg 返回错误信息
 */
function ValueValidator(errorMsg) {
	Validator.call(this);
	this.errorMsg = errorMsg;
}
ValueValidator.prototype.getErrorMsg = function() {
	return this.errorMsg;
}

/**
 * Function:关键字符输入验证器
 * @Extend ValueValidator
 */
function InputValidator(errorMsg) {
	if (!errorMsg || errorMsg == "") {
		errorMsg = "不能包含 单引号 引号 等系统关键字符";
	}
	ValueValidator.call(this, errorMsg);
}
InputValidator.prototype = new ValueValidator();
InputValidator.prototype.validate = function(value) {
	if (value == null || value == "") {
		return true;
	}
	return !(/^.*(\"|\').*$/.test(value));
}
			
/**
 * Function:必须输入验证器
 * @Extend ValueValidator
 */
function RequiredValidator(errorMsg) {
	if (!errorMsg || errorMsg == "") {
		errorMsg = "不能为空";
	}
	ValueValidator.call(this, errorMsg);
}
RequiredValidator.prototype = new ValueValidator();
RequiredValidator.prototype.validate = function(value) {
	return value != null && value != "";
}

/**
 * Function:正则表达式验证器
 * @Extend ValueValidator
 * @PrivateProperty regExp 正则表达式
 */
function RegExpValidator(regex, errorMsg) {
	if (!errorMsg || errorMsg == "") {
		errorMsg = "格式错误";
	}
	ValueValidator.call(this, errorMsg);
	this.regExp = new RegExp(regex);
}
RegExpValidator.prototype = new ValueValidator();
RegExpValidator.prototype.validate = function(value) {
	return (value == null || value == "") ? true : this.regExp.test(value);
}
			
/**
 * Function:最大长度验证器
 * @Extend ValueValidator
 * @PrivateProperty maxLength 允许的最大长度
 */
function MaxLengthValidator(maxLength, errorMsg) {
	if (!errorMsg || errorMsg == "") {
		errorMsg = "不能超过" + maxLength + "个字符";
	}
	ValueValidator.call(this, errorMsg);
	this.maxLength = maxLength;
}
MaxLengthValidator.prototype = new ValueValidator();
MaxLengthValidator.prototype.validate = function(value) {
	return (value == null || value == "") ? true : value.length <= this.maxLength;
}

/**
 * Function:最小长度验证器
 * @Extend ValueValidator
 * @PrivateProperty minLength 允许的最小长度
 */
function MinLengthValidator(minLength, errorMsg) {
	if (!errorMsg || errorMsg == "") {
		errorMsg = "不能少于" + minLength + "个字符";
	}
	ValueValidator.call(this, errorMsg);
	this.minLength = minLength;
}
MinLengthValidator.prototype = new ValueValidator();
MinLengthValidator.prototype.validate = function(value) {
	return (value == null || value == "") ? true : value.length >= this.minLength;
}

/**
 * Function:最大值验证器
 * @Extend ValueValidator
 * @PrivateProperty maxValue 允许的最大值
 */
function MaxValueValidator(maxValue, errorMsg) {
	if (!errorMsg || errorMsg == "") {
		errorMsg = "不能大于" + maxValue;
	}
	ValueValidator.call(this, errorMsg);
	this.maxValue = maxValue;
}
MaxValueValidator.prototype = new ValueValidator();
MaxValueValidator.prototype.validate = function(value) {
	return (value == null || value == "") ? true : value <= this.maxValue;
}

/**
 * Function:最小值验证器
 * @Extend ValueValidator
 * @PrivateProperty minValue 允许的最小值
 */
function MinValueValidator(minValue, errorMsg) {
	if (!errorMsg || errorMsg == "") {
		errorMsg = "不能小于" + minValue;
	}
	ValueValidator.call(this, errorMsg);
	this.minValue = minValue;
}
MinValueValidator.prototype = new ValueValidator();
MinValueValidator.prototype.validate = function(value) {
	return (value == null || value == "") ? true : value >= this.minValue;
}

/**
 * 可验证元素接口
 */
function Validateable() {
}
Validateable.prototype.validate = function() {
}

/**
 * Function:可验证字段
 * @Extend Validateable
 * @PrivateProperty htmlField html字段元素
 * @PrivateProperty errorMsg 出错时显示的信息
 * @PrivateProperty isValid 验证状态
 * @PrivateProperty validators 验证器列表
 * @PrivateProperty error 错误信息显示块
 * @PrivateProperty errorShowing 是否已经显示错误信息块
 * @PrivateMethod initValidators 初始化所有验证器
 * @PrivateMethod addValidate 添加一个验证器
 * @PrivateMethod getAttribute 获取命名属性
 * @PrivateMethod createErrorInfo 创建错误信息div显示块
 * @PublicMethod clearError 清楚错误信息块
 * @PublicMethod showError 显示错误信息块
 * @PrivateMethod showTip 显示提示
 * @PrivateMethod closeTip 关闭提示
 */
function Field(htmlField) {
	Validateable.call(this);
	this.htmlField = htmlField;
	this.errorMsg = null;
	this.isValid = true;
	this.validators = new Array();
	this.initValidators();
	this.error = null;
	this.errorShowing = false;
	
	this.onblur = null;
	this.onfocus = null;
	this.onmouseover = null;
	this.onmouseout = null;
	
	if (this.validators.length > 0) {
		var target = this;
		var onblur = htmlField.onblur;
		this.onblur = onblur;
		htmlField.onblur = function() {
			var result = execFunction(onblur);
			target.validate();
			if (typeof(result) != "undefined") {
				return result;
			}
		}
		var onfocus = htmlField.onfocus;
		this.onfocus = onfocus;
		htmlField.onfocus = function() {
			var result = execFunction(onfocus);
			target.clearError();
			if (typeof(result) != "undefined") {
				return result;
			}
		}
		var onmouseover = htmlField.onmouseover;
		this.onmouseover = onmouseover;
		htmlField.onmouseover = function() {
			var result = execFunction(onmouseover);
			target.showError();
			if (typeof(result) != "undefined") {
				return result;
			}
		}
		var onmouseout = htmlField.onmouseout;
		this.onmouseout = onmouseout;
		htmlField.onmouseout = function() {
			var result = execFunction(onmouseout);
			target.clearError();
			if (typeof(result) != "undefined") {
				return result;
			}
		}
	}
}
Field.prototype = new Validateable();

Field.prototype.reset = function() {
	this.errorMsg = null;
	this.isValid = true;
	this.validators = new Array();
	this.initValidators();
	this.error = null;
	this.errorShowing = false;
	
	if (this.validators.length > 0) {
		var target = this;
		var onblur = null;
		if (this.onblur) {
			onblur = this.onblur;
		} else {
			onblur = this.htmlField.onblur;
			this.onblur = onblur;
		}
		this.htmlField.onblur = function() {
			var result = execFunction(onblur);
			target.validate();
			if (typeof(result) != "undefined") {
				return result;
			}
		}
		var onfocus = null;
		if (this.onfocus) {
			onfocus = this.onfocus;
		} else {
			onfocus = this.htmlField.onfocus;
			this.onfocus = onfocus;
		}
		this.htmlField.onfocus = function() {
			var result = execFunction(onfocus);
			target.clearError();
			if (typeof(result) != "undefined") {
				return result;
			}
		}
		var onmouseover = null;
		if (this.onmouseover) {
			onmouseover = this.onmouseover;
		} else {
			onmouseover = this.htmlField.onmouseover;
			this.onmouseover = onmouseover;
		}
		this.htmlField.onmouseover = function() {
			var result = execFunction(onmouseover);
			target.showError();
			if (typeof(result) != "undefined") {
				return result;
			}
		}
		var onmouseout = null;
		if (this.onmouseout) {
			onmouseout = this.onmouseout;
		} else {
			onmouseout = this.htmlField.onmouseout;
			this.onmouseout = onmouseout;
		}
		this.htmlField.onmouseout = function() {
			var result = execFunction(onmouseout);
			target.clearError();
			if (typeof(result) != "undefined") {
				return result;
			}
		}
	}
}

Field.prototype.createErrorInfo = function() {
	this.error = document.createElement("div");
	this.error.style.position = "absolute";
	this.error.style.lineHeight = "20px";
	this.error.style.zIndex = "999";
	this.error.style.paddingLeft = "2px";
	this.error.style.paddingRight = "2px";
	this.error.style.backgroundColor = "#FFF2E9";
	this.error.style.color = "#EA5200";
	this.error.style.fontWeight = "bold";
	this.error.style.border = "1px solid #FF6600";
	this.error.style.left = getLeft(this.htmlField) + this.htmlField.offsetWidth + 4;
	this.error.style.top = getTop(this.htmlField) + 1;
}

Field.prototype.getErrorMsg = function() {
	return this.errorMsg;
}
Field.prototype.getAttribute = function(attrName) {
	return this.htmlField.getAttribute(attrName);
}
Field.prototype.initValidators = function() {
}
Field.prototype.addValidator = function(validator) {
	this.validators.push(validator);
}
Field.prototype.validate = function() {
	if (this.htmlField.getAttribute("disabled") || this.htmlField.style.display == "none") {
		return true;
	}
	this.htmlField.value = this.htmlField.value.replace(/^\s+|\s+$/g, "");	//过滤首尾空格
	for (var i = 0; i < this.validators.length; i ++) {
		var validator = this.validators[i];
		if (! validator.validate(this.htmlField.value)) {
			this.isValid = false;
			this.errorMsg = validator.getErrorMsg();
			this.showTip();
			return false;
		}
	}
	this.isValid = true;
	this.errorMsg = null;
	this.closeTip();
	return true;
}
Field.prototype.showError = function() {
	if (! this.isValid) {
		if (! this.error) {
			this.createErrorInfo();
		}
		this.error.innerHTML = "&nbsp;×&nbsp;" + this.errorMsg + "&nbsp;";
		this.errorShowing = true;
		document.body.appendChild(this.error);
	}
}
Field.prototype.clearError = function() {
	if (this.errorShowing) {
		document.body.removeChild(this.error);
		this.errorShowing = false;
	}
}
Field.prototype.showTip = function() {
}
Field.prototype.closeTip = function() {
}

/**
 * Function:文本输入框
 * @Extend Field
 * @PrivateProperty normalBorderColor 正常情况下的边框样式
 */
function TextField(textField) {
	Field.call(this, textField);
	this.normalBorderColor = textField.style.borderColor;
	this.normalBorderWidth = textField.style.borderWidth;
}
TextField.prototype = new Field();
TextField.prototype.showTip = function() {
	this.htmlField.style.borderWidth = "1px";
	this.htmlField.style.borderColor = "#FF0000";
}
TextField.prototype.closeTip = function() {
	this.htmlField.style.borderWidth = this.normalBorderWidth;
	this.htmlField.style.borderColor = this.normalBorderColor;
}
TextField.prototype.initValidators = function() {
	this.addValidator(new InputValidator(""));
	if (this.getAttribute("required")) {	//必须填写验证
		this.addValidator(new RequiredValidator(this.getAttribute("requiredMsg")));
	}
	var regex = this.getAttribute("regex");
	if (regex != null && regex != "") {	//正则表达式验证
		this.addValidator(new RegExpValidator(regex, this.getAttribute("regexMsg")));
	}
	var dataType = this.getAttribute("dataType");
	if (dataType != null && dataType != "") {	//常用数据类型验证
		this.addValidator(new RegExpValidator(favoriteRegExp[dataType], this.getAttribute("dataTypeMsg")));
	}
	var maxLength = this.getAttribute("maxLen");
	if (maxLength != null && maxLength != "") {	//最大长度验证器
		this.addValidator(new MaxLengthValidator(maxLength, this.getAttribute("maxLenMsg")));
	}
	var minLength = this.getAttribute("minLen");
	if (minLength != null && minLength != "") {	//最小长度验证器
		this.addValidator(new MinLengthValidator(minLength, this.getAttribute("minLenMsg")));
	}
	var maxValue = this.getAttribute("maxValue");
	if (maxValue != null && maxValue != "") {	//最大值验证器
		this.addValidator(new MaxValueValidator(maxValue, this.getAttribute("maxValueMsg")));
	}
	var minValue = this.getAttribute("minValue");
	if (minValue != null && minValue != "") {	//最小值验证器
		this.addValidator(new MinValueValidator(minValue, this.getAttribute("minValueMsg")));
	}
}

/**
 * Function:文件上载
 * @Extend Field
 * @PrivateProperty normalBorderColor 正常情况下的边框样式
 */
function FileField(textField) {
	Field.call(this, textField);
	this.normalBorderColor = textField.style.borderColor;
	this.normalBorderWidth = textField.style.borderWidth;
}
FileField.prototype = new Field();
FileField.prototype.showTip = function() {
	this.htmlField.style.borderWidth = "1px";
	this.htmlField.style.borderColor = "#FF0000";
}
FileField.prototype.closeTip = function() {
	this.htmlField.style.borderWidth = this.normalBorderWidth;
	this.htmlField.style.borderColor = this.normalBorderColor;
}
FileField.prototype.initValidators = function() {
	this.addValidator(new InputValidator(""));
	// 支持必填验证
	if (this.getAttribute("required")) {	//必须填写验证
		this.addValidator(new RequiredValidator(this.getAttribute("requiredMsg")));
	}
}

/**
 * Function:文本域
 * @Extend Field
 * @PrivateProperty normalBorderColor 正常情况下的边框样式
 */
function TextAreaField(textField) {
	Field.call(this, textField);
	this.normalBorderColor = textField.style.borderColor;
	this.normalBorderWidth = textField.style.borderWidth;
}
TextAreaField.prototype = new Field();
TextAreaField.prototype.showTip = function() {
	this.htmlField.style.borderWidth = "1px";
	this.htmlField.style.borderColor = "#FF0000";
}
TextAreaField.prototype.closeTip = function() {
	this.htmlField.style.borderWidth = this.normalBorderWidth;
	this.htmlField.style.borderColor = this.normalBorderColor;
}
TextAreaField.prototype.initValidators = function() {
	//支持必填验证，正则表达式验证，最大长度和最小长度验证
	if (this.getAttribute("required")) {	//必须填写验证
		this.addValidator(new RequiredValidator(this.getAttribute("requiredMsg")));
	}
	var regex = this.getAttribute("regex");
	if (regex != null && regex != "") {	//正则表达式验证
		this.addValidator(new RegExpValidator(regex, this.getAttribute("regexMsg")));
	}
	var maxLength = this.getAttribute("maxLen");
	if (maxLength != null && maxLength != "") {	//最大长度验证器
		this.addValidator(new MaxLengthValidator(maxLength, this.getAttribute("maxLenMsg")));
	}
	var minLength = this.getAttribute("minLen");
	if (minLength != null && minLength != "") {	//最小长度验证器
		this.addValidator(new MinLengthValidator(minLength, this.getAttribute("minLenMsg")));
	}
}

/**
 * Function:下拉选择框
 * @Extend Field
 */
function SelectField(selectField) {
	Field.call(this, selectField);
	this.normalBackgroundColor = this.htmlField.style.backgroundColor;
	var span = document.createElement("span");
	span.style.overflow = "hidden";
	this.htmlField.parentNode.insertBefore(span, this.htmlField);
	span.appendChild(this.htmlField);
	this.box = span;
	var target = this;
	var onchange = this.htmlField.onchange;
	this.htmlField.onchange = function() {
		var result = execFunction(onchange);
		target.validate();
		if (typeof(result) != "undefined") {
			return result;
		}
	}
}
SelectField.prototype = new Field();
SelectField.prototype.initValidators = function() {
	//选择框仅支持必选验证
	if (this.getAttribute("required")) {	//必须填写验证
		this.addValidator(new RequiredValidator(this.getAttribute("requiredMsg")));
	}
}
SelectField.prototype.showTip = function() {
	this.box.style.border = "1px solid #FF0000";
}
SelectField.prototype.closeTip = function() {
	this.box.style.border = "0px";
}

/**
 * Function 验证表单
 * @Extend Validateable
 * @PrivateProperty form html表单对象
 * @PrivateProperty fields 字段
 * @PrivateMethod addField 添加字段
 */
function Form(htmlForm) {
	Validateable.call(this);
	this.form = htmlForm;
	this.fields = new Array();
	for (var i = 0; i < this.form.elements.length; i ++) {
		var ele = this.form.elements[i];
		var field = createField(ele);
		if (field) {
			this.addField(field);
		}
	}
}
Form.prototype = new Validateable();
Form.prototype.addField = function(field) {
	this.fields.push(field);
}
Form.prototype.getField = function(field) {
	for (var i = 0; i < this.fields.length; i++) {
		if (this.fields[i].htmlField == field) {
			return this.fields[i];
		}
	}
}
Form.prototype.validate = function() {
	var result = true;
	for (var i = 0; i < this.fields.length; i ++) {
		if (! this.fields[i].validate()) {
			result = false;
		}
	}
	return result;
}

/**
 * 获取元素在页面中的top高度
 */
function getTop(e) {
	var offset = e.offsetTop;
	if (e.offsetParent != null) {
		offset += getTop(e.offsetParent);
	}
	return offset;
}

/**
 * 获取元素在页面中的left宽度
 */
function getLeft(e) {
	var offset = e.offsetLeft;
	if (e.offsetParent != null) {
		offset += getLeft(e.offsetParent);
	}
	return offset;
}

/**
 * 执行不带参数的函数
 */
function execFunction(func) {
	if (typeof(func) == "function") {
		return func();
	}
}

//创建字段的工厂方法
function createField(field) {
	if (field.tagName == "INPUT") {
		if (field.getAttribute("type") == "text") {
			return new TextField(field);
		}
		if (field.getAttribute("type") == "file") {
			return new FileField(field);
		}
	}
	if (field.tagName == "SELECT") {
		return new SelectField(field);
	}
	if (field.tagName == "TEXTAREA") {
		return new TextAreaField(field);
	}
	//....添加其他的字段类型
	return null;
}

//-----------------------------------------------------------------

//客户端相关

var domForms = new Array();
function initValidateForm(tForm) {
	domForms[tForm] = new Form(tForm);
	var onsubmit = tForm.onsubmit;
	tForm.onsubmit = function() {
		var result = execFunction(onsubmit);
		if (typeof(result) != "undefined") {
			return result && domForms[tForm].validate();
		} else {
			return domForms[tForm].validate();
		}
	}
}